//
//  main.m
//  第一个OC类
//
//  Created by 吴子维 on 2017/11/30.
//  Copyright © 2017年 Sunday. All rights reserved.
//

#import <Foundation/Foundation.h>

/*
 事物名称: iPhone
 属性: 颜色, 型号, cpu, 尺寸   == 成员变量
 行为:打电话, 发短信, 上网     == 成员方法
 
 C语言中函数分为声明和实现
 OC中定义一个类也分为声明和实现, 也就是说以后我们在OC中定义类, 就是在写类的声明和实现
 */

// 1.如何编写类的声明
// 以@interface开头 , 以@end结尾, 然后再class name对应的地方写上 事物名称, 也就是类名即可
// 注意: 类名的首字符必须大写
// 声明一个类的目的就是为了告诉系统, 我们这个类中有哪些属性和行为

// OC类声明中属性只能在写@interface和@end之间的{}中
// 注意: 编写OC类属性的时, 建议将所有属性的名称前面都加上_


typedef enum {
    kIColorBlack,
    KIColorWhite,
    kIColorTuHaoJin
} IColor;

// 类名后面的 :NSObject 是为了让我们的Iphone类具备创建对象的能力
@interface Iphone : NSObject
{
    //    注意: 默认情况下, OC对象中的属性是不能直接访问的
    @public // 只要让类中的属性公开, 以后就可以直接通过一个指向结构体的指针来操作对象中的属性
    float _model;
    int _cpu;
//    @private
    double _size;
//    @protected// 不加@public，@private，的情况下是默认@protected
//    int _color;
    IColor _color;
}

// 行为
/*
 OC中的行为和C语言中的函数一样, 都是用来保存一段特定功能的代码
 C语言中定义一个函数, 分为声明和实现, 声明写在.h中, 实现写在.c中
 OC中定义一个方法, 也分为声明和实现, 声明写在@interface中, 实现写在@implementation
 
 C语言的函数分为两种: 内部函数和外部函数
 OC中的方法也分为两种; 类方法和对象方法
 
 类方法只能用类名调用, 对象方法只能用对象调用
 OC中的类方法用+表示, OC中的对象方法用-表示
 
 编写C语言函数的规律: 1.确定函数名称 2.确定形参 3.确定返回值 4.确定返回值类型
 编写OC方法也有规律, 规律和C语言一模一样
 */

/*
 void about();
 void about()
 {
 printf("model = cpu = size = color");
 }
 */

// 注意: OC中的方法, 如果没有形参不需要写(), 而是直接写一个;
// 为什么OC中没有形参不需要写()呢? 因为OC方法中的()有特殊的用途, OC方法中的()是用来扩住数据类型的

- (void)aobut;

/*
 C语言的函数:
 没有返回值没有参数的
 有返回值没有参数的
 有返回值有参数的
 没有返回值有参数的
 */

// 有返回值没有参数的, 读取短信
- (char *)loadMessage;

// 有返回值有参数的, 打电话
// int signal(int number);
// 注意: OC中的方法如果有参数, 那么每个参数的数据类型前面必须加上一个:
// 注意: 当前这个有参数的方法它的方法名称是  signal:
//       冒号也是方法名称的一部分
- (int)signal:(int)number;

// 有返回值并且有多个参数的, 发短信
// int sendMessage(int number, char *content);
// 下面这个方法的方法名称是 sendMessage::
//- (int)sendMessage:(int)number :(char *)content;

// 为了提高我们的阅读性, OC方法允许我们给每个参数添加一个标签来说明当前参数的含义
// 注意: 标签也是方法名的一部分
// 方法名是 sendMessageWithNumber:andContent:
- (int)sendMessageWithNumber:(int)number andContent:(char *)content;

// 计算器
// 如果你不想每次使用方法都需要创建对象开辟存储空间
// 并且如果该方法中没有使用到属性(成员变量), 那么你可以把这个方法定义为类方法
// 对象方法用对象调用  类方法用类调用
//- (int)sumWithValue1:(int)value1 andValue2:(int)value2;

// 如果定义类方法, 类方法的写法和对象方法一模一样, 除了前面的-号不同以外 \
只需要将对象方法的-号换成+, 那么就定义了一个类方法
+ (int)sumWithValue1:(int)value1 andValue2:(int)value2;

+ (void)demo;

// 工具方法, 根据传入的整数返回对应的字符串
//- (NSString *)colorWithNumber:(IColor)number
+ (NSString *)colorWithNumber:(IColor)number;

@end




// 2.如何编写类的实现
// 以@implementation开头, 以@end结尾, 然后在class对应的地方写上声明时声明的类的名称, 必须和声明的类名一模一样
@implementation Iphone
// 行为的实现
- (void)about
{
//    NSLog(@"打印本机信息");
    // 如果在对象方法中想访问该对象的属性, 可以直接写上_属性名称即可
    NSLog(@"型号 = %f, cpu = %i, ");
}

- (char *)loadMessage
{
    char *content = "老婆老婆我们家我做主";
    return content;
}

- (int)signal:(int)number
{
    NSLog(@"打电话给%i",number);
    return 1;
}

- (int)sendMessageWithNumber:(int)number andContent:(char *)content
{
    NSLog(@"发短信给%i, 内容是%s",number, content);
    return 1;
}

/*
 类方法和对象方法的区别
 0. 对象方法以-开头
 类方法以+开头
 
 1. 对象方法必须用对象调用
 类方法必须用类来调用
 
 2. 对象方法中可以直接访问属性(成员变量)
 类方法中不可以直接访问属性(成员变量)
 
 3. 类方法和对象方法可以进行相互调用
 4.1对象方法中可以直接调用类方法
 4.2类方法中间接调用对象方法  (注意: 不建议这样使用)
 4.3类方法中可以直接调用其它类方法
 4.4对象方法中可以直接调用对象方法
 
 类方法的应用场景
 如果方法中没有使用到属性(成员变量), 那么能用类方法就用类方法
 类方法的执行效率比对象方法高
 
 类方法一般用于定义工具方法
 字符串查找
 文件操作
 数据库操作
 */

+(int)sumWithValue1:(int)value1 andValue2:(int)value2
{
    return value1 + value2;
}

+ (void)demo
{
    NSLog(@"Demo");
}

+ (NSString *)colorWithNumber:(IColor)number
{
    NSString *name;
    switch (number) {
        case 0:
            name = @"黑色";
            break;
        case 1:
            name = @"白色";
            break;
        case 2:
            name = @"土豪金";
            break;
        default:
            name = @"华强北";
            break;
    }
    
    return name;
}

@end


int main(int argc, const char * argv[]) {
    // 如何通过一个类来创建对象
    // 在OC中想要通过一个类来创建一个对象, 必须给类发送一个消息(好比C语言中调用函数一样)
    // 如何发送消息?   在OC中只要想要发送消息就先写上 [类名称/对象名称 方法名称];
    // 发送什么消息(调用什么方法)可以创建一个对象呢? new
    
    /*0
     只要通过一个类调用类的new方法, 也就是给类发送一个叫做new的消息之后
     系统内部就会做3件事情
     1. 为Iphone类创建出来得对象分配存储空间
     2. 初始化Iphone类创建出来的对象中的属性
     3. 返回Iphone类创建出来的对象对应的地址
     */
    
    // 通过一个Iphone类型的指针接收了 Iphone对象的地址
    // 如果使用给一个指针保存了某一个对象的地址, 那么我们就称这个指针位之为某个类型的对象
    // 利用Iphone类型的指针保存了Iphone对象的地址, 那么我们就称Iphone类型的指针p之为Iphone对象
    Iphone *p = [Iphone new];
    p->_size = 3.5;
//    p->_color = 0;
    p->_color = kIColorTuHaoJin;

    NSLog(@"当前手机颜色为%@",[Iphone colorWithNumber:kIColorTuHaoJin]);
    p->_model = 4;
    p->_cpu = 1;
    
    // OC中的类其实本质就是一个结构体, 所以p这个指针其实就是指向了一个结构体
    NSLog(@"size = %f, color = %i, model = %f, cpu = %i",p->_size,p->_color,p->_model,p->_cpu);
    
    struct Person
    {
        int age;
        char *name;
    };
    
    struct Person sp;
    struct Person *sip = &sp;
    
    (*sip).age = 30;
    (*sip).name = "wwz";
    
    sip->age = 29;
    sip->name = "AA";
    
    printf("age = %i, name = %s\n",sip->age,sip->name);
     // 什么是用于保存地址的? 指针

    // 如果给对象发消息(如果调用对象的方法)
    [p about];
    
//    [对象 消息名称(方法名称)]
    // 注意: OC中的NSLog对C语言的字符串支持不是很好, 如果返回的是中文的C语言字符串可能输出的是乱码, 也有可能什么都不输出
    char *content = [p loadMessage];
    NSLog(@"content = %s", content);
    
    [p signal:10086];
    
    [p sendMessageWithNumber:13700 andContent:"i like you"];
    
    [Iphone sumWithValue1:99 andValue2:1];
    
    [Iphone demo];
    
    void test1();// C语言式声明
    
    test1();

    return 0;
}

void test1()
{
    NSLog(@"类方法计算器 sum = %i",[Iphone sumWithValue1:99 andValue2:1]);
}
